package com.boot.ys.mybatisplus.Test;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 小程序uni-app项目的自动化重命名工具
 *
 * @author: 杨升
 * @date: 2025-05-31 13:48
 * @Version 1.0
 */

public class AboUniApp {

    public static void main(String[] args) {

        // 1. 直接定义项目路径
        String projectPath = "C:\\Users\\Acer\\Desktop\\1\\front";

        // 2. 定义替换规则（Key: 这里直接用拼音表名, Value: 改之后的拼音表名,我会下划线转驼峰的）
        Map<String, String> replacementMap = new LinkedHashMap<>();
        replacementMap.put("lajifenlei", "garbage_classification");     // 垃圾分类
        // 2. 把这个map的下划线驼峰转名称得到Map
        Map<String, String> camelHashMap = convertToCamelCase(replacementMap);

        // 数据全部装到这里面去
        LinkedHashMap<String, String> camelCaseMap = new LinkedHashMap<String, String>();


        // 循环打印和这个map
        for (Map.Entry<String, String> entry : camelHashMap.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());

            camelCaseMap.put(entry.getKey(), entry.getValue());
            // 替换router.js文件里面的内容 替换这三种情况
            // import yonghuList from '../pages/yonghu/list'
            // import yonghuDetail from '../pages/yonghu/detail'
            // import yonghuAdd from '../pages/yonghu/add'
            camelCaseMap.put(entry.getKey() + "List", entry.getValue() + "List");
            camelCaseMap.put(entry.getKey() + "Detail", entry.getValue() + "Detail");
            camelCaseMap.put(entry.getKey() + "Add", entry.getValue() + "Add");
        }

        // 5. 递归替换文件夹名称
        renameFolders(new File(projectPath), camelCaseMap);


        //.vue和.js文件里面的内容替换
        try {
            for (Map.Entry<String, String> entry : camelCaseMap.entrySet()) {
                updateXmlContent(projectPath, entry.getKey(), entry.getValue());
            }

            // 补偿机制，补偿这种情况   this.$http.get('option/yonghu/yonghu',
            // 上面运行的脚本会把这条变成下面的样子    this.$http.get('option/user_info/user_info',  这里其实第二个user_info是字段名称，应该要恢复为yonghu
            // 这里写个补偿机制解决这个问题
            for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
                updateJavaContent(projectPath, entry.getKey(), entry.getValue(), camelCaseMap);
            }

        } catch (Exception e) {
            System.out.println("更新vue和js文件内容失败!");
            e.printStackTrace();
        }


    }

    /**
     * 补偿文件脚本
     *
     * @param Path         项目根目录
     * @param oldClassName 就是旧的拼音表名，比如：yonghu
     * @param newClassName 新的英文表名带下划线 比如：user_info
     * @param camelCaseMap 转换后的驼峰表名，比如：userInfo
     * @throws IOException
     */
    static void updateJavaContent(String Path, String oldClassName, String newClassName, LinkedHashMap<String, String> camelCaseMap) throws IOException {
        java.nio.file.Path startPath = Paths.get(Path);

        // 包含的文件扩展名
        Set<String> set = new HashSet<>();
        set.add("vue");
        set.add("js");
        set.add("json");

        // 这里必须用这个有序的Map
        LinkedHashMap<String, String> map = new LinkedHashMap<>();

        // 匹配这种情况this.$http.get('option/userInfo/userInfo' 这里面的第一个user_info变为修改为英文的表名
        // userInfo -> 第二参数应该是旧的英文表名应该是
        map.put("option/" + camelCaseMap.get(oldClassName) + "/", "option/" + newClassName + "/");

        // 上面的map执行后代码会变为：this.$http.get('option/user_info/userInfo' 现在修改最后一个userInfo为旧表名（也就是旧的字段名）
        // 最终是要变成    this.$http.get('option/user_info/yonghu' 程序才能正常运行
        map.put("option/" + newClassName + "/" + camelCaseMap.get(oldClassName), "option/" + newClassName + "/" + oldClassName);


        // 匹配这种情况res = await this.$api.option(`garbageClassification`,`garbageClassification`,{});
        // 这个是替换第一个garbageClassification
        map.put(
                "option\\(`" + camelCaseMap.get(oldClassName) + "`,",
                "option(`" + newClassName + "`,"
        );
        // 这个是替换第二个garbageClassification \\(是为了转义分号
        // 程序要成为这样子才能正常运行 res = await this.$api.option(`garbage_classification`,`lajifenlei`,{});
        map.put("option\\(`" + newClassName + "`,`" + camelCaseMap.get(oldClassName) + "`",
                "option(`" + newClassName + "`,`" + oldClassName + "`");

        Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                // 获取文件名
                String fileName = file.getFileName().toString();

                // 检查文件是否有扩展名（即是否包含点号）
                int dotIndex = fileName.lastIndexOf('.');
                if (dotIndex > 0) {  // 确保点号不在开头位置
                    // 提取扩展名（去掉点号，并转为小写）
                    String fileExtension = fileName.substring(dotIndex + 1).toLowerCase();

                    // 检查扩展名是否在允许的集合中
                    if (set.contains(fileExtension)) {
                        // 只有符合条件的文件才会被处理
                        processFileContent(file, map);
                    }
                }
                return FileVisitResult.CONTINUE;
            }
        });

        System.out.println("前端程序的补偿机制完成!");

    }

    /**
     * 更新文件内容
     *
     * @param Path         项目根目录
     * @param oldClassName 拼音表名 jiudianxinxi
     * @param newClassName 表英文表名 hotelInfo
     * @Date: 2025/4/10
     */
    static void updateXmlContent(String Path, String oldClassName, String newClassName) throws IOException {

        java.nio.file.Path startPath = Paths.get(Path);

        // 包含的文件扩展名
        Set<String> set = new HashSet<>();
        set.add("vue");
        set.add("js");
        set.add("json");

        Map<String, String> map = new LinkedHashMap<>();

        // 下面所有有的替换都需要带上特定表示这种情况的符号，比如：' 防止更新出现错误
        // 替换这种情况：'jiudianxinxi'
        map.put("'" + oldClassName + "'", "'" + newClassName + "'");

        // 替换这种情况：/jiudianxinxi/
        map.put("/" + oldClassName + "/", "/" + newClassName + "/");
        //
        // 替换这种情况："jiudianxinxi"
        map.put("\"" + oldClassName + "\"", "\"" + newClassName + "\"");

        // 替换这种情况：'/jiudianxinxi'
        map.put("'/" + oldClassName + "'", "'/" + newClassName + "'");

        // 替换这种（import bumenxinxi from ）情况：import bumenxinxi from '@/views/modules/bumenxinxi/list'
        map.put("import " + oldClassName + " from", "import " + newClassName + " from");

        // 正则表达式：匹配 `import` + 任意空白 + 旧类名 + 任意空白 + `from`
        // 匹配这种情况（import deptInfo from）：import deptInfo from '@/views/modules/deptInfo/list'
        map.put("import\\s+" + Pattern.quote(oldClassName) + "\\s+from\\b", "import " + newClassName + " from");

        // 匹配这种情况 url: `yonghu/info/${id}`,
        map.put("`" + oldClassName + "/", "`" + newClassName + "/");

        // 匹配这种情况 `yonghu`
        map.put("`" + oldClassName + "`", "`" + newClassName + "`");

        // 匹配这种情况（/qichexinxi'） url: '/index/qichexinxi'
        map.put("/" + oldClassName + "'", "/" + newClassName + "'");
        /**
         *  {
         *  path: '/bumenxinxi',
         *  name: '部门信息',
         *  component: bumenxinxi
         *  }
         *     新增：精准替换 component: 后的独立变量名（兼容任意数量的空格）
         *     // 正向否定预查，确保后面没有字母/数字/下划线
         */
        // 替换 component 后的类名（兼容任意数量的空格）
        map.put("component:\\s+" + Pattern.quote(oldClassName) + "(?![\\w])", "component: " + newClassName);

        // 替换这种情况url: "bumenxinxi/page",（这里是双引号）
        map.put("\"" + oldClassName + "/", "\"" + newClassName + "/");

        // 替换这种情况url: 'bumenxinxi/page",（这里是单引号）
        map.put("'" + oldClassName + "/", "'" + newClassName + "/");

        Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                // 获取文件名
                String fileName = file.getFileName().toString();

                // 检查文件是否有扩展名（即是否包含点号）
                int dotIndex = fileName.lastIndexOf('.');
                if (dotIndex > 0) {  // 确保点号不在开头位置
                    // 提取扩展名（去掉点号，并转为小写）
                    String fileExtension = fileName.substring(dotIndex + 1).toLowerCase();

                    // 检查扩展名是否在允许的集合中
                    if (set.contains(fileExtension)) {
                        // 只有符合条件的文件才会被处理
                        processFileContent(file, map);
                    }
                }
                return FileVisitResult.CONTINUE;
            }
        });

        System.out.println("更新前端完成!");
    }

    static void processFileContent(Path file, Map<String, String> map) throws IOException {
        String content = new String(Files.readAllBytes(file), "UTF-8");


        String result = content;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            result = result.replaceAll(entry.getKey(), entry.getValue());
        }

        if (!result.equals(content)) {
            System.out.println("Updating content of: " + file);
            Files.write(file, result.getBytes("UTF-8"), StandardOpenOption.TRUNCATE_EXISTING);
        }
    }

    /**
     * 递归遍历并重命名文件夹
     *
     * @param directory 当前目录
     * @param renameMap 重命名映射表
     */
    public static void renameFolders(File directory, Map<String, String> renameMap) {
        if (!directory.isDirectory()) {
            return;
        }

        File[] subDirs = directory.listFiles(File::isDirectory);
        if (subDirs == null) {
            return;
        }

        for (File subDir : subDirs) {
            // 先递归处理子目录
            renameFolders(subDir, renameMap);

            // 获取当前文件夹名称
            String folderName = subDir.getName();

            // 检查是否需要重命名
            if (renameMap.containsKey(folderName)) {
                String newName = renameMap.get(folderName);
                File newDir = new File(subDir.getParent(), newName);

                if (subDir.renameTo(newDir)) {
                    System.out.println("重命名成功: " + subDir.getAbsolutePath() +
                            " -> " + newDir.getAbsolutePath());
                } else {
                    System.err.println("重命名失败: " + subDir.getAbsolutePath());
                }
            }
        }
    }


    /**
     * 将Map中的value从下划线命名转为驼峰命名
     */
    public static Map<String, String> convertToCamelCase(Map<String, String> originalMap) {
        return originalMap.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey, // 保持key不变
                        entry -> underscoreToCamelCase(entry.getValue()), // 转换value
                        (oldValue, newValue) -> newValue,
                        LinkedHashMap::new
                ));
    }

    /**
     * 下划线转驼峰命名
     * 示例: "primary_line" -> "primaryLine"
     */
    public static String underscoreToCamelCase(String underscoreStr) {
        if (underscoreStr == null || underscoreStr.isEmpty()) {
            return underscoreStr;
        }

        // 分割下划线
        String[] parts = underscoreStr.split("_");
        if (parts.length == 0) {
            return underscoreStr;
        }

        // 第一个单词全小写
        StringBuilder result = new StringBuilder(parts[0].toLowerCase());

        // 后续单词首字母大写
        for (int i = 1; i < parts.length; i++) {
            if (!parts[i].isEmpty()) {
                result.append(parts[i].substring(0, 1).toUpperCase())
                        .append(parts[i].substring(1).toLowerCase());
            }
        }

        return result.toString();
    }


}
